/*
 * ServerRegistrationHandler.cpp
 *
 *  Created on: Feb 9, 2012
 *      Author: rudi
 */
#include <wx/url.h>
#include <wx/tokenzr.h>
#include <wx/txtstrm.h>
#include "ServerRegistrationHandler.h"
#include "App.h"
#include "Configuration.h"

/**
 * class ServerRegistrationHandler::ServerInfo
 */

ServerRegistrationHandler::ServerInfo::ServerInfo(): mIpAddress(), mPort(-1), mLevel(), mFree(-1)
{
	// Nothing to do yet
}

ServerRegistrationHandler::ServerInfo::ServerInfo(const ServerRegistrationHandler::ServerInfo& serverInfo): mIpAddress(serverInfo.mIpAddress),
																											mPort(serverInfo.mPort),
																											mLevel(serverInfo.mLevel),
																											mFree(serverInfo.mFree)
{
	// Nothing to do yet
}

/**
 * class ServerRegistrationHandler
 */

const wxString ServerRegistrationHandler::HOST(wxT("http://pixelbypixel.uw.hu/index.php"));

bool ServerRegistrationHandler::registerServer(const ServerInfo& serverInfo, wxString& response)
{
	// Check if the registration is enabled or not
	if(true == wxGetApp().getConfiguration()->getNetworkConfiguration()->registerServer())
		return ServerRegistrationHandler::executeHttpRequest(serverInfo, wxT("add"), response);

	// If no registration needed, just return with true
	return true;
}

bool ServerRegistrationHandler::updateServer(const ServerInfo& serverInfo, wxString& response)
{
	// Check if the registration is enabled or not
	if(true == wxGetApp().getConfiguration()->getNetworkConfiguration()->registerServer())
		return ServerRegistrationHandler::executeHttpRequest(serverInfo, wxT("update"), response);

	// If no registration needed, just return with true
	return true;
}

bool ServerRegistrationHandler::deregisterServer(const ServerInfo& serverInfo, wxString& response)
{
	// Check if the registration is enabled or not
	if(true == wxGetApp().getConfiguration()->getNetworkConfiguration()->registerServer())
		return ServerRegistrationHandler::executeHttpRequest(serverInfo, wxT("delete"), response);

	// If no registration needed, just returjn with true
	return true;
}

bool ServerRegistrationHandler::queryServers(bool justFree, std::vector<ServerInfo>& response)
{
	wxString responseString;
	ServerInfo serverInfo;
	wxStringTokenizer tokenizer;
	bool ok = false;

	response.clear();
	// Fetch only free servers if needed
	if(true == justFree)
		serverInfo.setFree(1);
	if(false == ServerRegistrationHandler::executeHttpRequest(serverInfo, wxT("query"), responseString))
		return false;
	// Response should looks like this: OK: <ip1> <port1> <level1> <free1> <ip2> <port2> and so on...
	// Tokenize the response string by the spaces
	tokenizer.SetString(responseString, wxT(" "));
	if(false == tokenizer.HasMoreTokens())
		return false;
	// Just drop the first token: it is the "OK: " start string
	tokenizer.GetNextToken();
	// Try to get all of the tokens. If any of them is missing, return false
	while(true == tokenizer.HasMoreTokens())
	{
		wxString ip = tokenizer.GetNextToken();
		wxString port;
		wxString level;
		wxString free;

		ok = false;
		if(false == tokenizer.HasMoreTokens())
			break;
		port = tokenizer.GetNextToken();
		if(false == tokenizer.HasMoreTokens())
			break;
		level = tokenizer.GetNextToken();
		if(false == tokenizer.HasMoreTokens())
			break;
		free = tokenizer.GetNextToken();
		serverInfo.clear();
		serverInfo.setIpAddress(ip);
		serverInfo.setPort(wxAtoi(port.c_str()));
		serverInfo.setLevel(level);
		serverInfo.setFree(wxAtoi(free.c_str()));
		response.push_back(serverInfo);
		ok = true;
	}
	if(false == ok)
	{
		response.clear();

		return false;
	}

	return true;
}

/**
 * Private methods
 */

wxString ServerRegistrationHandler::getSearchPart(const ServerInfo& serverinfo)
{
	wxString returnString(wxT("?"));
	bool first = true;
	bool searchPartAdded = false;

	// If the port contains a valid value
	if(serverinfo.getPort() != -1)
	{
		returnString += wxT("port=") + wxString::Format(wxT("%d"), serverinfo.getPort());
		first = false;
		searchPartAdded = true;
	}
	// If the level contains a valid value
	if(serverinfo.getLevel() != wxT(""))
	{
		// If it is not the first parameter add the "&" character to the result
		if(false == first)
			returnString += wxT("&");
		returnString += wxT("level=") + serverinfo.getLevel();
		first = false;
		searchPartAdded = true;
	}
	// If the free variable is set
	if(serverinfo.getFree() != -1)
	{
		// If it is not the first parameter add the "&" character to the result
		if(false == first)
			returnString += wxT("&");
		returnString += wxT("free=") + wxString::Format(wxT("%d"), serverinfo.getFree());
		searchPartAdded = true;
	}
	// This is needed because the caller does not know how to add more search parameter - e.g. method
	if(true == searchPartAdded)
		returnString += wxT("&");

	return returnString;
}

bool ServerRegistrationHandler::executeHttpRequest(const ServerInfo& serverInfo, const wxString& method, wxString& response)
{
	wxURL url(HOST + ServerRegistrationHandler::getSearchPart(serverInfo) + wxT("method=") + method);
	wxInputStream* input = NULL;
	wxTextInputStream* textInput = NULL;
	bool returnValue = true;

	if(wxURL_NOERR != url.GetError())
	{
		response = wxT("Could not connect to server!");

		return false;
	}
	// Set the proxy if it is configured
	if(true == wxGetApp().getConfiguration()->getNetworkConfiguration()->getProxyConfiguration()->useProxy())
	{
		wxString host = wxGetApp().getConfiguration()->getNetworkConfiguration()->getProxyConfiguration()->getProxyAddress()->getHost();
		int port = wxGetApp().getConfiguration()->getNetworkConfiguration()->getProxyConfiguration()->getProxyAddress()->getPort();

		url.SetProxy(host + wxT(":") + wxString::Format(wxT("%d"), port));
		static_cast<wxHTTP&>(url.GetProtocol()).SetHeader(wxT("Host"), wxT("pixelbypixel.uw.hu"));
	}
	input = url.GetInputStream();
	if(NULL == input)
	{
		response = wxT("Could not send request to server");

		return false;
	}
	// Try to read the response
	textInput = new wxTextInputStream(*input);
	while(input->CanRead())
		response += textInput->ReadLine();
	// If the response starts with ERROR, the request was not successfully executed on the server side
	if(response.Contains(wxT("ERROR: ")))
		returnValue = false;
	delete textInput;
	delete input;

	return returnValue;
}
